/**
 * Copyright (c) 2014.
 */
package konggao.util.bean;

import java.lang.reflect.InvocationTargetException;

import org.apache.commons.beanutils.PropertyUtilsBean;
import org.apache.commons.lang3.StringUtils;

/**
 * @format Eclipse format:http://maven.apache.org/developers/maven-eclipse-codestyle.xml
 * @Email hua.wanghuawh@alibaba-inc.com
 * @Date 2014年4月14日 下午8:27:59
 * @Class PropertyUtilsBean.java
 */
public class PropertyUtilsBeanProxy
    extends PropertyUtilsBean
{
    private PropertyUtilsBeanProxyConfig config;

    /**
     * 
     */
    public PropertyUtilsBeanProxy()
    {
        super();
        this.config = new PropertyUtilsBeanProxyConfig();
    }

    /**
     * @param config
     */
    public PropertyUtilsBeanProxy( PropertyUtilsBeanProxyConfig config )
    {
        super();
        this.config = config;
    }

    @Override
    public void setSimpleProperty( Object bean, String name, Object value )
        throws IllegalAccessException, InvocationTargetException, NoSuchMethodException
    {
        boolean override =
            StringUtils.isNotEmpty( value == null ? null : value.toString() )
                || ( value == null && config.isEnabled( PropertyUtilsBeanProxyFeature.OVERRIDE_CASE_NULL ) )
                || ( value != null && StringUtils.isEmpty( value.toString() ) && config.isEnabled( PropertyUtilsBeanProxyFeature.OVERRIDE_CASE_EMPTY ) );
        if ( override )
        {
            super.setSimpleProperty( bean, name, value );
        }
    }

    public static class PropertyUtilsBeanProxyConfig
    {
        private int features;

        /**
         * @param features
         */
        public PropertyUtilsBeanProxyConfig()
        {
            super();
            this.features = collectFeatureDefaults( PropertyUtilsBeanProxyFeature.class );
        }

        public PropertyUtilsBeanProxyConfig with( PropertyUtilsBeanProxyFeature... features )
        {
            for ( PropertyUtilsBeanProxyFeature f : features )
            {
                this.features |= f.getMask();
            }
            return this;
        }

        public final boolean isEnabled( PropertyUtilsBeanProxyFeature f )
        {
            return ( features & f.getMask() ) != 0;
        }
    }

    public static <F extends Enum<F> & ConfigFeature> int collectFeatureDefaults( Class<F> enumClass )
    {
        int flags = 0;
        for ( F value : enumClass.getEnumConstants() )
        {
            if ( value.enabledByDefault() )
            {
                flags |= value.getMask();
            }
        }
        return flags;
    }

    /**
     * 通过配置来指定setSimpleProperty逻辑
     * 
     * @format Eclipse format:http://maven.apache.org/developers/maven-eclipse-codestyle.xml
     * @Email hua.wanghuawh@alibaba-inc.com
     * @Date 2014年4月14日 下午8:39:00
     * @Class PropertyUtilsBeanProxy.java
     */
    public static enum PropertyUtilsBeanProxyFeature
        implements ConfigFeature
    {
        /**
         * setSimpleProperty(bean, name, value),value=null的时候,是否覆盖,默认false不覆盖
         */
        OVERRIDE_CASE_NULL( false ),
        /**
         * setSimpleProperty(bean, name, value),value=""的时候,是否覆盖,默认false不覆盖
         */
        OVERRIDE_CASE_EMPTY( false ), ;
        private final boolean _defaultState;

        private PropertyUtilsBeanProxyFeature( boolean defaultState )
        {
            _defaultState = defaultState;
        }

        public boolean enabledByDefault()
        {
            return _defaultState;
        }

        public int getMask()
        {
            return ( 1 << ordinal() );
        }
    }

    public interface ConfigFeature
    {
        /**
         * Accessor for checking whether this feature is enabled by default.
         */
        public boolean enabledByDefault();

        /**
         * Returns bit mask for this feature instance
         */
        public int getMask();
    }
}
